﻿<html>
	<script src="math.js"></script>
	<script src="multiply-matrices.js"></script>
	<script>

// Make matrices for converting to and from an arbitrary RGB color space,
// given the x,y chromaticities of red, green, blue and white.
// To use these matrices, the RGB components are assumed be
// linearized and in the range 0 to 1.
// http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html

// Horribly hacky, non interactive utility. Edit the file to pick
// another color space and read the results from the console :P


		// these are for ITU Rec BT.2020
		// const xred=0.708 ;
		// const yred=0.292 ;

		// const xgreen=0.170 ;
		// const ygreen=0.797 ;

		// const xblue=0.131 ;
		// const yblue=0.046 ;

		// these are for sRGB
		const xred=0.640 ;
		const yred=0.330 ;

		const xgreen=0.300 ;
		const ygreen=0.600 ;

		const xblue=0.150 ;
		const yblue=0.060 ;

		// these are for display-p3
		// const xred=0.680 ;
		// const yred=0.320 ;

		// const xgreen=0.265 ;
		// const ygreen=0.690 ;

		// const xblue=0.150 ;
		// const yblue=0.060 ;

		// ProPhoto
		// const xred=0.7347 ;
		// const yred=0.2653 ;

		// const xgreen=0.1596 ;
		// const ygreen=0.8404  ;

		// const xblue=0.0366 ;
		// const yblue=0.0001  ;

		// AdobeRGB, for testing

		// const xred=0.640 ;
		// const yred=0.330 ;

		// const xgreen=0.210 ;
		// const ygreen=0.710 ;

		// const xblue=0.150 ;
		// const yblue=0.060 ;


		// D65 from ASTM E308-01
		const XWhite = 0.95047;
		const YWhite = 1.00000;
		const ZWhite = 1.08883;

		// D50 from ASTM E308-01
		// const XWhite = 0.96422;
		// const YWhite = 1.00000;
		// const ZWhite = 0.82521;



		// Relative XYZ values. Copy-paste-o-rama
		// method from http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html

		var XRed=xred/yred;
		var YRed=1;
		var ZRed=(1 - xred - yred)/yred;

		var XGreen=xgreen/ygreen;
		var YGreen=1;
		var ZGreen=(1 - xgreen - ygreen)/ygreen;

		var XBlue=xblue/yblue;
		var YBlue=1;
		var ZBlue=(1 - xblue - yblue)/yblue;

		var white = math.matrix([XWhite, YWhite, ZWhite]);
		console.log("White X Y Z")
		console.log(white.valueOf());
		var primaries = math.matrix([
			[XRed, XGreen, XBlue],
			[YRed, YGreen, YBlue],
			[ZRed, ZGreen, ZBlue]
		]);
		console.log("Primaries X Y Z")
		console.log(primaries.valueOf());

		var iprimaries = math.inv(primaries);
		console.log(iprimaries.valueOf());

		// S is easier if it ends up as an array than a matrix
		// but we use matrix math to calculate it
		var S = math.multiply(iprimaries,white).valueOf();

		var M = [
			[S[0] * XRed, S[1] * XGreen, S[2] * XBlue],
			[S[0] * YRed, S[1] * YGreen, S[2] * YBlue],
			[S[0] * ZRed, S[1] * ZGreen, S[2] * ZBlue]
		];

		console.log("RGB to XYZ");
		console.log(M);
		console.log("XYZ to RGB");
		console.log(math.inv(math.matrix(M)).valueOf());

		// for code verification: with AdobeRGB primaries, correct result is
		// M =
		//	[[0.5767309  0.1855540  0.1881852],
 		//	 [0.2973769  0.6273491  0.0752741],
 		//	 [0.0270343  0.0706872  0.9911085]];
		// Minv =
		//	[[2.0413690 -0.5649464 -0.3446944],
		//	 [-0.9692660  1.8760108  0.0415560],
 		//	 [0.0134474 -0.1183897  1.0154096]];
	</script>
</html>